Ethereum & Polygon¶

Fees in Relationship to Network Interest¶

NOTE: Since we wrote the models in R, they could not be uploaded as an .ipynb. We uploaded them as well:¶

Our Macroeconomic models can be found at: 1) https://jonahb.xyz/eth_model.html --> Our Ethereum ADL Model

2) https://jonahb.xyz/poly_model.html --> Our Polygon ADL Model

3) https://jonahb.xyz/eth_poly_comparison.html --> Comparing the fees of Ethereum and Polygon

Analysis of these models are found in the presentation :)

Please see these links after reading through the notebook¶

Also, if you have problems navigating the python notebook, please see our online version at https://jonahb.xyz/CIS_233_HW_4_(FINAL).html

Imports¶

In [1]:
#imports
import plotly.express as px
import matplotlib.pyplot as plt
import plotly.graph_objects as go
plt.style.use("ggplot")

import pandas as pd
import numpy as np
import scipy
from scipy import stats
from datetime import datetime, timedelta

import seaborn as sns
Matplotlib is building the font cache; this may take a moment.
In [ ]:
 

Upload and Organize Data¶

In [2]:
#transaction data
eth_df_1 = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/eth-fee-data.csv') # in ETH
eth_df_2 = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/eth-fee-usd.csv') # in USD
eth_df = eth_df_1.merge(eth_df_2, left_on='DAY', right_on='DAY') # in both
eth_df['DAY'] = pd.to_datetime(eth_df['DAY'], format='%Y-%m-%d %H:%M:%S')

poly_df_1 = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/poly-fee-data.csv') # in MATIC
poly_df_2 = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/poly-fee-usd.csv') # in USD
poly_df = poly_df_1.merge(poly_df_2, left_on='DAY', right_on='DAY') # in both
poly_df['DAY'] = pd.to_datetime(poly_df['DAY'], format='%Y-%m-%d %H:%M:%S')


#interest data
#Numbers represent search interest relative to the highest point on the chart for the given region and time. A value of 100 is the peak popularity for the term. A value of 50 means that the term is half as popular. A score of 0 means there was not enough data for this term.
crypto_interest_df = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/Cryptocurrency_Interest.csv')
crypto_interest_df["Week"] = pd.to_datetime(crypto_interest_df['Week'], format='%m/%d/%y')

ethereum_interest_df = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/Ethereum_Interest.csv')
ethereum_interest_df["Week"] = pd.to_datetime(ethereum_interest_df['Week'], format='%m/%d/%y')

poly_interest_df = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/Polygon_Interest.csv')
poly_interest_df["Week"] = pd.to_datetime(poly_interest_df['Week'], format='%m/%d/%y')

matic_interest_df = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/MATIC_Interest.csv')
matic_interest_df["Week"] = pd.to_datetime(matic_interest_df['Week'], format='%m/%d/%y')

# price data
ethereum_price = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/eth.csv') 
ethereum_price['time'] = pd.to_datetime(ethereum_price['time'], format='%Y-%m-%d')

matic_price = pd.read_csv('/Users/jonahburian/Desktop/CIS/CIS233/PROJECT/project-real/chain-data/matic_eth.csv') 
matic_price['time'] = pd.to_datetime(matic_price['time'], format='%Y-%m-%d')

#cut off dates that google trends does not have good data for
cut_off_date = datetime.strptime("01/01/2020", "%d/%m/%Y")
cut_off_date2 = datetime.strptime("03/04/2022", "%d/%m/%Y")


eth_df = eth_df[(eth_df['DAY'] > cut_off_date) & (eth_df['DAY'] < cut_off_date2)]
poly_df = poly_df[(poly_df['DAY'] > cut_off_date) & (poly_df['DAY'] < cut_off_date2)]
crypto_interest_df = crypto_interest_df[(crypto_interest_df['Week'] > cut_off_date) & (crypto_interest_df['Week'] < cut_off_date2)]
ethereum_interest_df = ethereum_interest_df[(ethereum_interest_df['Week'] > cut_off_date) & (ethereum_interest_df['Week'] < cut_off_date2)]
poly_interest_df = poly_interest_df[(poly_interest_df['Week'] > cut_off_date) & (poly_interest_df['Week'] < cut_off_date2)]
matic_interest_df = matic_interest_df[(matic_interest_df['Week'] > cut_off_date) & (matic_interest_df['Week'] < cut_off_date2)]
ethereum_price = ethereum_price[(ethereum_price['time'] > cut_off_date) & (ethereum_price['time'] < cut_off_date2)]
matic_price = matic_price[(matic_price['time'] > cut_off_date) & (matic_price['time'] < cut_off_date2)]

#dataframes from last month, year
cut_off_date_month = datetime.strptime("12/04/2021", "%d/%m/%Y")
cut_off_date_year = datetime.strptime("03/04/2021", "%d/%m/%Y")
eth_df_month = eth_df[(eth_df['DAY'] > cut_off_date_month) & (eth_df['DAY'] < cut_off_date2)]
poly_df_month = poly_df[(poly_df['DAY'] > cut_off_date_month) & (poly_df['DAY'] < cut_off_date2)]
eth_df_year = eth_df[(eth_df['DAY'] > cut_off_date_year) & (eth_df['DAY'] < cut_off_date2)]
poly_df_year = poly_df[(poly_df['DAY'] > cut_off_date_year) & (poly_df['DAY'] < cut_off_date2)]

Evolution of Interest Over Time¶

  • Especially after normalization, all interest (based on Google Trends) in trends are relatively the same (with the expectation of the initial adoption in mid-2020 of Polygon where Polygon saw a lot of interest.)
In [3]:
#normalizing interest
crypto_interest_df["Interest_Z_score"] = (crypto_interest_df["Interest"] - np.mean(crypto_interest_df["Interest"]))/scipy.stats.sem(crypto_interest_df["Interest"])
ethereum_interest_df["Interest_Z_score"] = (ethereum_interest_df["Interest"] - np.mean(ethereum_interest_df["Interest"]))/scipy.stats.sem(ethereum_interest_df["Interest"])
poly_interest_df["Interest_Z_score"] = (poly_interest_df["Interest"] - np.mean(poly_interest_df["Interest"]))/scipy.stats.sem(poly_interest_df["Interest"])
matic_interest_df["Interest_Z_score"] = (matic_interest_df["Interest"] - np.mean(matic_interest_df["Interest"]))/scipy.stats.sem(matic_interest_df["Interest"])
In [4]:
#charting interest over time - normal
# set up plotly figure for normal interest over time
fig = go.Figure()

# add different traces
fig.add_trace(go.Scatter(
    name="Crypto Interest",
    x=crypto_interest_df['Week'],
    y=crypto_interest_df['Interest_Z_score'],
    hovertext=crypto_interest_df['Interest_Z_score'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))
fig.add_trace(go.Scatter(
    name="Ethereum Interest",
    x=ethereum_interest_df['Week'],
    y=ethereum_interest_df['Interest_Z_score'],
    hovertext=ethereum_interest_df['Interest_Z_score'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

fig.add_trace(go.Scatter(
    name="MATIC Interest",
    x=matic_interest_df['Week'],
    y=matic_interest_df['Interest_Z_score'],
    hovertext=matic_interest_df['Interest_Z_score'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.add_trace(go.Scatter(
    name="Polygon Interest",
    x=poly_interest_df['Week'],
    y=poly_interest_df['Interest_Z_score'],
    hovertext=poly_interest_df['Interest_Z_score'],
    hoverinfo="text",
    marker=dict(
        color="purple"
    ),
    showlegend=True
))

fig.update_layout(
    title="Normalized Interest",
    xaxis_title="Date",
    yaxis_title="Interest Based on Normalization of Google Interest Score",
    legend_title="Legend",
    showlegend=True
)

fig.show()
In [5]:
#charting interest over time - rolling
rolling_val = 10
fig = go.Figure()
# add different traces
crypto_interest_df['Interest_Rolling'] = crypto_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Crypto Interest",
    x=crypto_interest_df['Week'],
    y=crypto_interest_df['Interest_Rolling'],
    hovertext=crypto_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

ethereum_interest_df['Interest_Rolling'] = ethereum_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Ethereum Interest",
    x=ethereum_interest_df['Week'],
    y=ethereum_interest_df['Interest_Rolling'],
    hovertext=ethereum_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

matic_interest_df['Interest_Rolling'] = matic_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="MATIC Interest",
    x=matic_interest_df['Week'],
    y=matic_interest_df['Interest_Rolling'],
    hovertext=matic_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

poly_interest_df['Interest_Rolling'] = poly_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Polygon Interest",
    x=poly_interest_df['Week'],
    y=poly_interest_df['Interest_Rolling'],
    hovertext=poly_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="purple"
    ),
    showlegend=True
))

fig.update_layout(
    title="Normalized",
    xaxis_title="Date",
    yaxis_title="Interest Based on Normalization of Google Interest Score",
    legend_title="Legend",
    showlegend=True
)

fig.show()

Statistics on Transaction Fees Over Different Periods of Time¶

  • Important: note the scales (Ethereum scale is way higher)
  • Both chains have greater mean fees and variance has been higher in more recent timeframes
  • Polygon’s variance has increased more in recent months but remains lower than Ethereum when set on comparable scales.
In [6]:
#Ethereum Mean
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Mean = [np.mean(eth_df["AVG_FEE_USD"]), np.mean(eth_df_year["AVG_FEE_USD"]), np.mean(eth_df_month["AVG_FEE_USD"])]
plt.bar(Dates, Mean)
plt.title('Ethereum: Mean Fee USD')
plt.xlabel('Date')
plt.ylabel('Mean Fee USD')
plt.show()
In [7]:
#Ethereum Variance
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Var = [np.var(eth_df["AVG_FEE_USD"]), np.var(eth_df_year["AVG_FEE_USD"]), np.var(eth_df_month["AVG_FEE_USD"])]
plt.bar(Dates, Var)
plt.title('Ethereum: Variance of Fee USD')
plt.xlabel('Date')
plt.ylabel('Variance of Fee USD')
plt.show()
In [8]:
#Polygon Mean
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Mean = [np.mean(poly_df["AVG_FEE_USD"]), np.mean(poly_df_year["AVG_FEE_USD"]), np.mean(poly_df_month["AVG_FEE_USD"])]
plt.bar(Dates, Mean)
plt.title('Polygon: Mean Fee USD')
plt.xlabel('Date')
plt.ylabel('Mean Fee USD')
plt.show()
In [9]:
#Polygon Variance
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Var = [np.var(poly_df["AVG_FEE_USD"]), np.var(poly_df_year["AVG_FEE_USD"]), np.var(poly_df_month["AVG_FEE_USD"])]
plt.bar(Dates, Var)
plt.title('Polygon: Variance of Fee USD')
plt.xlabel('Date')
plt.ylabel('Variance of Fee USD')
plt.show()

Statistics on Transactions Over Different Periods of Time¶

  • For both chains, transaction volume has remained roughly constant over time and the variance of transaction volume has decreased.
  • The lower transaction volume on Polygon initially can be attributed to the chain not yet being fully adopted.
  • Conclusion: Supply has remained steady on both chains. This is unsurprising given that there is a limited amount of blockspace and blocks tend to be nearly filled.
In [10]:
#Ethereum Mean
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Mean = [np.mean(eth_df["TOTAL_TRANSACTIONS"]), np.mean(eth_df_year["TOTAL_TRANSACTIONS"]), np.mean(eth_df_month["TOTAL_TRANSACTIONS"])]
plt.bar(Dates, Mean)
plt.title('Ethereum: Mean Transaction Volume')
plt.xlabel('Date')
plt.ylabel('Mean Transaction Volume')
plt.show()
In [11]:
#Ethereum Variance
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Var = [np.var(eth_df["TOTAL_TRANSACTIONS"]), np.var(eth_df_year["TOTAL_TRANSACTIONS"]), np.var(eth_df_month["TOTAL_TRANSACTIONS"])]
plt.bar(Dates, Var)
plt.title('Ethereum: Variance of Transaction Volume')
plt.xlabel('Date')
plt.ylabel('Variance of Transaction Volume')
plt.show()
In [12]:
#Polygon Mean
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Mean = [np.mean(poly_df["TOTAL_TRANSACTIONS"]), np.mean(poly_df_year["TOTAL_TRANSACTIONS"]), np.mean(poly_df_month["TOTAL_TRANSACTIONS"])]
plt.bar(Dates, Mean)
plt.title('Polygon: Mean Transaction Volume')
plt.xlabel('Date')
plt.ylabel('Mean Transaction Volume')
plt.show()
In [13]:
#Polygon Variance
Dates = ['Since Jan 2020', 'Since Last Year', 'Since 4 Months']
Var = [np.var(poly_df["TOTAL_TRANSACTIONS"]), np.var(poly_df_year["TOTAL_TRANSACTIONS"]), np.var(poly_df_month["TOTAL_TRANSACTIONS"])]
plt.bar(Dates, Var)
plt.title('Polygon: Variance of Transaction Volume')
plt.xlabel('Date')
plt.ylabel('Variance of Transaction Volume')
plt.show()

Comparing Transaction Fees Across Blockchains¶

  • Ethereum has more variable fee movement than Polygon and both saw spikes in fees during early-2022. We hypothesise that there was a structural break around January possibly due to market forces.
In [14]:
#normalize transaction fee data
eth_df["AVG_FEE_USD_Z_SCORE"] = (eth_df["AVG_FEE_USD"] - np.mean(eth_df["AVG_FEE_USD"]))/scipy.stats.sem(eth_df["AVG_FEE_USD"])
poly_df["AVG_FEE_USD_Z_SCORE"] = (poly_df["AVG_FEE_USD"] - np.mean(poly_df["AVG_FEE_USD"]))/scipy.stats.sem(poly_df["AVG_FEE_USD"])
In [15]:
#rolling normalized transaction fees
rolling_val = 30
eth_df['Fee_Rolling'] = eth_df["AVG_FEE_USD_Z_SCORE"].rolling(rolling_val).mean()

# set up plotly figure
fig = go.Figure()
# add line / traces to figure
fig.add_trace(go.Scatter(
    name="Ethereum",
    x=eth_df['DAY'],
    y=eth_df['Fee_Rolling'],
    hovertext=eth_df['Fee_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

poly_df['Fee_Rolling'] = poly_df["AVG_FEE_USD_Z_SCORE"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Polygon",
    x=poly_df['DAY'],
    y=poly_df['Fee_Rolling'],
    hovertext=poly_df['Fee_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

fig.update_layout(
    title="Average Fees over Time (Normalized)",
    xaxis_title="Date",
    yaxis_title="Average Fee (USD)",
    legend_title="Legend",
    showlegend=True
)

fig.show()

Interest and Transaction Fees Over Time¶

  • Once combining both normalized interest and normalized transaction fees (USD) over time, no obvious patterns appear (other than the spike in January 2022). More analysis was needed.
In [16]:
#ethereum interest with ethereum transaction fees
#rolling 
rolling_val = 7

# set up plotly figure
fig = go.Figure()
# add line / traces to figure
crypto_interest_df['Interest_Rolling'] = crypto_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Crypto Interest",
    x=crypto_interest_df['Week'],
    y=crypto_interest_df['Interest_Rolling'],
    hovertext=crypto_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

ethereum_interest_df['Interest_Rolling'] = ethereum_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Ethereum Interest",
    x=ethereum_interest_df['Week'],
    y=ethereum_interest_df['Interest_Rolling'],
    hovertext=ethereum_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

eth_df['Fee_Rolling'] = eth_df["AVG_FEE_USD_Z_SCORE"].rolling(rolling_val).mean()

# add line / trace 1 to figure
fig.add_trace(go.Scatter(
    name="Ethereum Avg Fee (USD)",
    x=eth_df['DAY'],
    y=eth_df['Fee_Rolling'],
    hovertext=eth_df['Fee_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.update_layout(
    title="Comparison Between Trends with Interest and Fees",
    xaxis_title="Date",
    yaxis_title="Normalized Z Scores",
    legend_title="Legend",
    showlegend=True
)

fig.show()
In [17]:
#polygon interest with polygon transaction fees
#rolling 
rolling_val = 10

# set up plotly figure
fig = go.Figure()
# add line / traces to figure

matic_interest_df['Interest_Rolling'] = matic_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Matic Interest",
    x=matic_interest_df['Week'],
    y=matic_interest_df['Interest_Rolling'],
    hovertext=matic_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

poly_interest_df['Interest_Rolling'] = poly_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Polygon Interest",
    x=poly_interest_df['Week'],
    y=poly_interest_df['Interest_Rolling'],
    hovertext=poly_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))


poly_df['Fee_Rolling'] = poly_df["AVG_FEE_USD_Z_SCORE"].rolling(rolling_val+20).mean()

# add line / trace 1 to figure
fig.add_trace(go.Scatter(
    name="Polygon Avg Fee (USD)",
    x=poly_df['DAY'],
    y=poly_df['Fee_Rolling'],
    hovertext=poly_df['Fee_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.update_layout(
    title="Comparison Between Trends with Interest and Fees",
    xaxis_title="Date",
    yaxis_title="Normalized Z Scores",
    legend_title="Legend",
    showlegend=True
)

fig.show()
In [18]:
#cut off dates before Jan (when there was lots of volatility that skewed data)
cut_off_date = datetime.strptime("01/01/2020", "%d/%m/%Y")
cut_off_date2 = datetime.strptime("01/01/2022", "%d/%m/%Y")
eth_df_prejan = eth_df[(eth_df['DAY'] > cut_off_date) & (eth_df['DAY'] < cut_off_date2)]
poly_df_prejan = poly_df[(poly_df['DAY'] > cut_off_date) & (poly_df['DAY'] < cut_off_date2)]
crypto_interest_df_prejan = crypto_interest_df[(crypto_interest_df['Week'] > cut_off_date) & (crypto_interest_df['Week'] < cut_off_date2)]
ethereum_interest_df_prejan = ethereum_interest_df[(ethereum_interest_df['Week'] > cut_off_date) & (ethereum_interest_df['Week'] < cut_off_date2)]
poly_interest_df_prejan = poly_interest_df[(poly_interest_df['Week'] > cut_off_date) & (poly_interest_df['Week'] < cut_off_date2)]
matic_interest_df_prejan = matic_interest_df[(matic_interest_df['Week'] > cut_off_date) & (matic_interest_df['Week'] < cut_off_date2)]
In [19]:
#ethereum interest with ethereum transaction fees (pre-Jan)
#rolling 
rolling_val = 10

# set up plotly figure
fig = go.Figure()
# add line / traces to figure
crypto_interest_df_prejan['Interest_Rolling'] = crypto_interest_df_prejan["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Crypto Interest",
    x=crypto_interest_df_prejan['Week'],
    y=crypto_interest_df_prejan['Interest_Rolling'],
    hovertext=crypto_interest_df_prejan['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

ethereum_interest_df_prejan['Interest_Rolling'] = ethereum_interest_df_prejan["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Ethereum Interest",
    x=ethereum_interest_df_prejan['Week'],
    y=ethereum_interest_df_prejan['Interest_Rolling'],
    hovertext=ethereum_interest_df_prejan['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

eth_df_prejan['Fee_Rolling'] = eth_df_prejan["AVG_FEE_USD_Z_SCORE"].rolling(rolling_val+20).mean()

# add line / trace 1 to figure
fig.add_trace(go.Scatter(
    name="Ethereum Avg Fee (USD)",
    x=eth_df_prejan['DAY'],
    y=eth_df_prejan['Fee_Rolling'],
    hovertext=eth_df_prejan['Fee_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.update_layout(
    title="Comparison Between Trends with Interest and Fees",
    xaxis_title="Date",
    yaxis_title="Normalized Z Scores",
    legend_title="Legend",
    showlegend=True
)
fig.show()
/var/folders/yq/fp50ycz10h17wdmr_wgy552m0000gn/T/ipykernel_73275/1326364032.py:8: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

/var/folders/yq/fp50ycz10h17wdmr_wgy552m0000gn/T/ipykernel_73275/1326364032.py:21: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

/var/folders/yq/fp50ycz10h17wdmr_wgy552m0000gn/T/ipykernel_73275/1326364032.py:34: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

In [20]:
#Polygon interest with polygon transaction fees (pre-Jan)
#rolling 
rolling_val = 10

# set up plotly figure
fig = go.Figure()
# add line / traces to figure
matic_interest_df_prejan['Interest_Rolling'] = matic_interest_df_prejan["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Matic Interest",
    x=matic_interest_df_prejan['Week'],
    y=matic_interest_df_prejan['Interest_Rolling'],
    hovertext=matic_interest_df_prejan['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

poly_interest_df_prejan['Interest_Rolling'] = poly_interest_df_prejan["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Polygon Interest",
    x=poly_interest_df_prejan['Week'],
    y=poly_interest_df_prejan['Interest_Rolling'],
    hovertext=poly_interest_df_prejan['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

poly_df_prejan['Fee_Rolling'] = poly_df_prejan["AVG_FEE_USD_Z_SCORE"].rolling(rolling_val+20).mean()

# add line / trace 1 to figure
fig.add_trace(go.Scatter(
    name="Polygon Avg Fee (USD)",
    x=poly_df_prejan['DAY'],
    y=poly_df_prejan['Fee_Rolling'],
    hovertext=poly_df_prejan['Fee_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.update_layout(
    title="Comparison Between Trends with Interest and Fees",
    xaxis_title="Date",
    yaxis_title="Normalized Z Scores",
    legend_title="Legend",
    showlegend=True
)
fig.show()
/var/folders/yq/fp50ycz10h17wdmr_wgy552m0000gn/T/ipykernel_73275/957952431.py:8: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

/var/folders/yq/fp50ycz10h17wdmr_wgy552m0000gn/T/ipykernel_73275/957952431.py:21: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

/var/folders/yq/fp50ycz10h17wdmr_wgy552m0000gn/T/ipykernel_73275/957952431.py:34: SettingWithCopyWarning:


A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy

Interest and Price Over Time¶

In [21]:
#ethereum interest with ethereum transaction fees
#rolling 
rolling_val = 10

# set up plotly figure
fig = go.Figure()
# add line / traces to figure
crypto_interest_df['Interest_Rolling'] = crypto_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Crypto Interest",
    x=crypto_interest_df['Week'],
    y=crypto_interest_df['Interest_Rolling'],
    hovertext=crypto_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

ethereum_interest_df['Interest_Rolling'] = ethereum_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Ethereum Interest",
    x=ethereum_interest_df['Week'],
    y=ethereum_interest_df['Interest_Rolling'],
    hovertext=ethereum_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

ethereum_price["AdrActCnt_Z_SCORE"] = (ethereum_price["AdrActCnt"] - np.mean(ethereum_price["AdrActCnt"]))/scipy.stats.sem(ethereum_price["AdrActCnt"])
ethereum_price['Price_Rolling'] = ethereum_price["AdrActCnt_Z_SCORE"].rolling(rolling_val+20).mean()

# add line / trace 1 to figure
fig.add_trace(go.Scatter(
    name="Ethereum Price (USD)",
    x=ethereum_price['time'],
    y=ethereum_price['Price_Rolling'],
    hovertext=ethereum_price['Price_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.update_layout(
    title="Comparison Between Trends with Interest and Prices",
    xaxis_title="Date",
    yaxis_title="Normalized Z Scores",
    legend_title="Legend",
    showlegend=True
)
fig.show()
In [22]:
#polygon interest with polygon transaction fees
#rolling 
rolling_val = 10

# set up plotly figure
fig = go.Figure()
# add line / traces to figure
crypto_interest_df['Interest_Rolling'] = crypto_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
matic_interest_df['Interest_Rolling'] = matic_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Matic Interest",
    x=matic_interest_df['Week'],
    y=matic_interest_df['Interest_Rolling'],
    hovertext=matic_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="orange"
    ),
    showlegend=True
))

poly_interest_df['Interest_Rolling'] = poly_interest_df["Interest_Z_score"].rolling(rolling_val).mean()
fig.add_trace(go.Scatter(
    name="Polygon Interest",
    x=poly_interest_df['Week'],
    y=poly_interest_df['Interest_Rolling'],
    hovertext=poly_interest_df['Interest_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="blue"
    ),
    showlegend=True
))

matic_price["AdrActCnt_Z_SCORE"] = (matic_price["AdrActCnt"] - np.mean(matic_price["AdrActCnt"]))/scipy.stats.sem(matic_price["AdrActCnt"])
matic_price['Price_Rolling'] = matic_price["AdrActCnt_Z_SCORE"].rolling(rolling_val+20).mean()

# add line / trace 1 to figure
fig.add_trace(go.Scatter(
    name="Polygon Price (USD)",
    x=matic_price['time'],
    y=matic_price['Price_Rolling'],
    hovertext=matic_price['Price_Rolling'],
    hoverinfo="text",
    marker=dict(
        color="green"
    ),
    showlegend=True
))

fig.update_layout(
    title="Comparison Between Trends with Interest and Prices",
    xaxis_title="Date",
    yaxis_title="Normalized Z Scores",
    legend_title="Legend",
    showlegend=True
)
fig.show()

In Depth Analysis:¶

Ethereum: Average Fees & Number of Transaction Over Time¶

  • The number of transactions appear to remain stable.
  • Average fees are more volatile and every month looks different.
  • This seems to indicate that fee volatility is caused by demand shifts (not supply).
In [23]:
cut_off_date3 = datetime.strptime("31/03/2021", "%d/%m/%Y")
cut_off_date4 = datetime.strptime("01/04/2022", "%d/%m/%Y")

eth_for_plot = eth_df[['DAY','AVG_FEE_USD', 'TOTAL_TRANSACTIONS']]
eth_for_plot = eth_for_plot[(eth_for_plot['DAY'] > cut_off_date3) & (eth_for_plot['DAY'] < cut_off_date4)]
eth_for_plot['day'] = pd.DatetimeIndex(eth_for_plot['DAY']).day
eth_for_plot['month'] = pd.DatetimeIndex(eth_for_plot['DAY']).strftime("%b-%y")
eth_for_plot['month-'] = pd.DatetimeIndex(eth_for_plot['DAY']).month
In [24]:
sns.set_theme(style="dark")

g = sns.relplot(
    data=eth_for_plot,
    x="day", y="AVG_FEE_USD", col="month", hue="month",
    kind="line", palette="crest", linewidth=4, zorder=5,
    col_wrap=3, height=2, aspect=1.5, legend=False,
)

# Iterate over each subplot to customize further
for month, ax in g.axes_dict.items():

    # Add the title as an annotation within the plot
    ax.text(.8, .85, month, transform=ax.transAxes, fontweight="bold")

    # Plot every year's time series in the background
    sns.lineplot(
        data=eth_for_plot, x="day", y="AVG_FEE_USD", units="month",
        estimator=None, color=".7", linewidth=1, ax=ax,
    )

# Reduce the frequency of the x axis ticks
ax.set_xticks(ax.get_xticks()[::2])

# Tweak the supporting aspects of the plot
g.set_titles("")
g.set_axis_labels("", "Average Fee USD")
g.tight_layout()
In [25]:
poly_for_plot = poly_df[['DAY','AVG_FEE_USD', 'TOTAL_TRANSACTIONS']]
poly_for_plot = poly_for_plot[(poly_for_plot['DAY'] > cut_off_date3) & (poly_for_plot['DAY'] < cut_off_date4)]
poly_for_plot['day'] = pd.DatetimeIndex(poly_for_plot['DAY']).day
poly_for_plot['month'] = pd.DatetimeIndex(poly_for_plot['DAY']).strftime("%b-%y")
poly_for_plot['month-'] = pd.DatetimeIndex(poly_for_plot['DAY']).month


sns.set_theme(style="dark")
g = sns.relplot(
    data=poly_for_plot,
    x="day", y="AVG_FEE_USD", col="month", hue="month",
    kind="line", palette="crest", linewidth=4, zorder=5,
    col_wrap=3, height=2, aspect=1.5, legend=False,
)

# Iterate over each subplot to customize further
for month, ax in g.axes_dict.items():

    # Add the title as an annotation within the plot
    ax.text(.8, .85, month, transform=ax.transAxes, fontweight="bold")

    # Plot every year's time series in the background
    sns.lineplot(
        data=poly_for_plot, x="day", y="AVG_FEE_USD", units="month",
        estimator=None, color=".7", linewidth=1, ax=ax,
    )

# Reduce the frequency of the x axis ticks
ax.set_xticks(ax.get_xticks()[::2])

# Tweak the supporting aspects of the plot
g.set_titles("")
g.set_axis_labels("", "Average Fee USD")
g.tight_layout()

Polygon: Average Fees & Number of Transaction Over Time¶

  • The number of transactions appear to remain stable.
  • Average fees remain stable, except January 2022.
  • This seems to indicate that fee volatility is caused by demand shifts (not supply).
In [26]:
poly_for_plot = poly_df[['DAY','AVG_FEE_USD', 'TOTAL_TRANSACTIONS']]
poly_for_plot = poly_for_plot[(poly_for_plot['DAY'] > cut_off_date3) & (poly_for_plot['DAY'] < cut_off_date4)]
poly_for_plot['day'] = pd.DatetimeIndex(poly_for_plot['DAY']).day
poly_for_plot['month'] = pd.DatetimeIndex(poly_for_plot['DAY']).strftime("%b-%y")
poly_for_plot['month-'] = pd.DatetimeIndex(poly_for_plot['DAY']).month


sns.set_theme(style="dark")
g = sns.relplot(
    data=poly_for_plot,
    x="day", y="AVG_FEE_USD", col="month", hue="month",
    kind="line", palette="crest", linewidth=4, zorder=5,
    col_wrap=3, height=2, aspect=1.5, legend=False,
)

# Iterate over each subplot to customize further
for month, ax in g.axes_dict.items():

    # Add the title as an annotation within the plot
    ax.text(.8, .85, month, transform=ax.transAxes, fontweight="bold")

    # Plot every year's time series in the background
    sns.lineplot(
        data=poly_for_plot, x="day", y="AVG_FEE_USD", units="month",
        estimator=None, color=".7", linewidth=1, ax=ax,
    )

# Reduce the frequency of the x axis ticks
ax.set_xticks(ax.get_xticks()[::2])

# Tweak the supporting aspects of the plot
g.set_titles("")
g.set_axis_labels("", "Average Fee USD")
g.tight_layout()
In [27]:
sns.set_theme(style="dark")
g = sns.relplot(
    data=poly_for_plot,
    x="day", y="TOTAL_TRANSACTIONS", col="month", hue="month",
    kind="line", palette="crest", linewidth=4, zorder=5,
    col_wrap=3, height=2, aspect=1.5, legend=False,
)

# Iterate over each subplot to customize further
for month, ax in g.axes_dict.items():

    # Add the title as an annotation within the plot
    ax.text(.8, .85, month, transform=ax.transAxes, fontweight="bold")

    # Plot every year's time series in the background
    sns.lineplot(
        data=poly_for_plot, x="day", y="TOTAL_TRANSACTIONS", units="month",
        estimator=None, color=".7", linewidth=1, ax=ax,
    )

# Reduce the frequency of the x axis ticks
ax.set_xticks(ax.get_xticks()[::2])

# Tweak the supporting aspects of the plot
g.set_titles("")
g.set_axis_labels("", "Total Transactions")
g.tight_layout()

Ethereum and Polygon Heatmaps: Last 3 months of Transaction Fees (USD)¶

  • Heat maps, where the darker the color means less volatility show that Ethereum prices are more volatile than Polygon prices in high volatility times.
  • Polygon delivers better on the promise of lower volatility.
In [28]:
#Ethereum
cut_off_date5 = datetime.strptime("31/12/2021", "%d/%m/%Y")
eth_for_plot = eth_for_plot[(eth_for_plot['DAY'] > cut_off_date5)]
eth_for_plot["AVG_FEE_USD"] = round(eth_for_plot["AVG_FEE_USD"]).astype(int)
eth_for_plot_L = eth_for_plot.pivot("day", "month-", "AVG_FEE_USD")
# Draw a heatmap with the numeric values in each cell
f, ax = plt.subplots(figsize=(12, 8))
sns.heatmap(eth_for_plot_L, annot=True, linewidths=.5, ax=ax)
Out[28]:
<AxesSubplot:xlabel='month-', ylabel='day'>
In [29]:
# Polygon
poly_for_plot = poly_for_plot[(poly_for_plot['DAY'] > cut_off_date5)]
poly_for_plot_L = poly_for_plot.pivot("day", "month-", "AVG_FEE_USD")
# Draw a heatmap with the numeric values in each cell
f, ax = plt.subplots(figsize=(12, 8))
sns.heatmap(poly_for_plot_L, annot=True, linewidths=.5, ax=ax)
Out[29]:
<AxesSubplot:xlabel='month-', ylabel='day'>

Fees vs. Interest Linear Regression¶

  • Naive linear regressions on average fees versus normalized interest show a positive relationship worth exploring.
In [30]:
# Ethereum
ethereum_tx_interest_crypto = eth_df[['DAY','AVG_FEE_USD', 'AVG_FEE_USD_Z_SCORE']].merge(crypto_interest_df, left_on='DAY', right_on='Week')
poly_tx_interest_crypto = poly_df[['DAY','AVG_FEE_USD', 'AVG_FEE_USD_Z_SCORE']].merge(crypto_interest_df, left_on='DAY', right_on='Week')


tips = sns.load_dataset("tips")
g = sns.jointplot(x="Interest_Z_score", y="AVG_FEE_USD_Z_SCORE", data=ethereum_tx_interest_crypto,
                  kind="reg", truncate=False,
                  color="m", height=7)
In [31]:
# Polygon
g = sns.jointplot(x="Interest_Z_score", y="AVG_FEE_USD_Z_SCORE", data=poly_tx_interest_crypto,
                  kind="reg", truncate=False,
                  color="m", height=7)

Smooth kernel density with marginal histograms for Fees vs. Interest¶

In [32]:
#Ethereum:
sns.set_theme(style="white")

g = sns.JointGrid(data=ethereum_tx_interest_crypto, x="Interest", y="AVG_FEE_USD", space=0)
g.plot_joint(sns.kdeplot,
             fill=True,
             thresh=0, levels=100, cmap="rocket")
g.plot_marginals(sns.histplot, color="#03051A", alpha=1, bins=25)
Out[32]:
<seaborn.axisgrid.JointGrid at 0x7f90f1a9bac0>
In [33]:
# Polygon
g = sns.JointGrid(data=poly_tx_interest_crypto, x="Interest", y="AVG_FEE_USD", space=0)
g.plot_joint(sns.kdeplot,
             fill=True,
             thresh=0, levels=100, cmap="rocket")
g.plot_marginals(sns.histplot, color="#03051A", alpha=1, bins=25)
Out[33]:
<seaborn.axisgrid.JointGrid at 0x7f91103bedc0>

Ethereum vs Polygon Fees Regression¶

  • A naive linear regression on the normalized average fees against each other shows that fees between the networks are positively correlated.
  • This may be due to people switching to Polygon and/or some external factor like market movement. The latter is more likely the cause of the majority of the effect.
In [34]:
e_temp = eth_df[['DAY', 'AVG_FEE_USD', 'AVG_FEE_USD_Z_SCORE']]
e_temp = e_temp.rename(columns={"AVG_FEE_USD": "ETH_AVG_FEE_USD", "AVG_FEE_USD_Z_SCORE": "ETH_AVG_FEE_USD_Z_SCORE"})
poly_temp = poly_df[['DAY', 'AVG_FEE_USD', 'AVG_FEE_USD_Z_SCORE']]
poly_temp = poly_temp.rename(columns={"AVG_FEE_USD": "POLY_AVG_FEE_USD", "AVG_FEE_USD_Z_SCORE": "POLY_AVG_FEE_USD_Z_SCORE"})
price_temp = e_temp.merge(poly_temp, left_on='DAY', right_on='DAY') # in both



g = sns.jointplot(x="ETH_AVG_FEE_USD_Z_SCORE", y="POLY_AVG_FEE_USD_Z_SCORE", data=price_temp,
                  kind="reg", truncate=False,
                  color="m", height=7)

Macroeconomic Analysis¶

NOTE: Our Macroeconomic models can be found at:

1) https://jonahb.xyz/eth_model.html --> Our Ethereum ADL Model

2) https://jonahb.xyz/poly_model.html --> Our Polygon ADL Model

3) https://jonahb.xyz/eth_poly_comparison.html --> Comparing the fees of Ethereum and Polygon

In [ ]: